﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

using Daiz.Library;

namespace Daiz.NES.Reuben.ProjectManagement
{
    public class PaletteManager : IXmlIO
    {
        public event EventHandler<TEventArgs<PaletteInfo>> PaletteAdded;
        public event EventHandler<TEventArgs<PaletteInfo>> PaletteRemoved;
        public event EventHandler PalettesSaved;

        public List<PaletteInfo> Palettes { get; private set; }
        private Dictionary<Guid, PaletteInfo> paletteLookup;

        public PaletteManager()
        {
            Palettes = new List<PaletteInfo>();
            paletteLookup = new Dictionary<Guid, PaletteInfo>();
            Default();
        }

        public void Default()
        {
            Palettes.Clear();

            AddNewPalette("Map", new byte[] { 0x0F, 0x0F, 0x30, 0x3C, 0x0F, 0x36, 0x27, 0x37, 0x0F, 0x21, 0x2A, 0x37, 0x0F, 0x30, 0x16, 0x37, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x17, 0x36, 0x0F, 0x0F, 0x17, 0x36, 0x0F, 0x0F, 0x30, 0x16, 0x0F });
            AddNewPalette("Plains", new byte[] { 0x3C, 0x0F, 0x30, 0x3C, 0x3C, 0x0F, 0x36, 0x27, 0x3C, 0x0F, 0x2A, 0x1A, 0x3C, 0x0F, 0x31, 0x21, 0x3C, 0x00, 0x00, 0x00, 0x3C, 0x0F, 0x30, 0x16, 0x3C, 0x0F, 0x30, 0x2A, 0x3C, 0x0F, 0x36, 0x27 });
            AddNewPalette("Fortress", new byte[] { 0x0F, 0x0F, 0x30, 0x3C, 0x0F, 0x07, 0x36, 0x27, 0x0F, 0x06, 0x28, 0x16, 0x0F, 0x00, 0x30, 0x10, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x06, 0x30, 0x16, 0x0F, 0x0F, 0x30, 0x2C, 0x0F, 0x07, 0x36, 0x27 });
            AddNewPalette("Hilly", new byte[] { 0x3C, 0x0F, 0x30, 0x3C, 0x3C, 0x0F, 0x36, 0x27, 0x3C, 0x0F, 0x2A, 0x1A, 0x3C, 0x0F, 0x2A, 0x12, 0x3C, 0x00, 0x00, 0x00, 0x3C, 0x0F, 0x30, 0x16, 0x3C, 0x0F, 0x30, 0x2A, 0x3C, 0x0F, 0x36, 0x27 });
            AddNewPalette("Sky", new byte[] { 0x3C, 0x0F, 0x30, 0x3C, 0x3C, 0x0F, 0x36, 0x27, 0x3C, 0x0F, 0x2A, 0x1A, 0x3C, 0x0F, 0x30, 0x21, 0x3C, 0x00, 0x00, 0x00, 0x3C, 0x0F, 0x30, 0x16, 0x3C, 0x0F, 0x30, 0x2A, 0x3C, 0x0F, 0x36, 0x27 });
            AddNewPalette("Piranha Plant", new byte[] { 0x37, 0x0F, 0x30, 0x3C, 0x37, 0x0F, 0x36, 0x27, 0x37, 0x0F, 0x2A, 0x1A, 0x37, 0x0F, 0x30, 0x12, 0x37, 0x00, 0x00, 0x00, 0x37, 0x0F, 0x30, 0x16, 0x37, 0x0F, 0x30, 0x2A, 0x37, 0x0F, 0x36, 0x27 });
            AddNewPalette("Water", new byte[] { 0x12, 0x0F, 0x30, 0x3C, 0x12, 0x0F, 0x36, 0x27, 0x12, 0x0F, 0x01, 0x2C, 0x12, 0x0F, 0x25, 0x10, 0x12, 0x00, 0x00, 0x00, 0x12, 0x0F, 0x30, 0x16, 0x12, 0x0F, 0x30, 0x2A, 0x12, 0x0F, 0x30, 0x27 });
            AddNewPalette("Mushroom", new byte[] { 0x0F, 0x0F, 0x30, 0x3C, 0x0F, 0x3C, 0x30, 0x3B, 0x0F, 0x27, 0x30, 0x17, 0x0F, 0x12, 0x31, 0x21, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x30, 0x16, 0x0F, 0x0F, 0x30, 0x2A, 0x0F, 0x0F, 0x30, 0x27 });
            AddNewPalette("Pipe", new byte[] { 0x0F, 0x0F, 0x30, 0x3C, 0x0F, 0x0F, 0x36, 0x27, 0x0F, 0x0B, 0x3B, 0x1B, 0x0F, 0x0F, 0x0C, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0C, 0x30, 0x16, 0x0F, 0x0C, 0x30, 0x2A, 0x0F, 0x0C, 0x36, 0x27 });
            AddNewPalette("Desert", new byte[] { 0x37, 0x0F, 0x30, 0x3C, 0x37, 0x0F, 0x36, 0x27, 0x37, 0x0F, 0x27, 0x17, 0x37, 0x0F, 0x31, 0x21, 0x37, 0x00, 0x00, 0x00, 0x37, 0x0F, 0x30, 0x16, 0x37, 0x0F, 0x30, 0x2A, 0x37, 0x0F, 0x36, 0x27 });
            AddNewPalette("Airship", new byte[] { 0x3C, 0x0F, 0x30, 0x3C, 0x3C, 0x0F, 0x36, 0x27, 0x3C, 0x0F, 0x30, 0x10, 0x3C, 0x0F, 0x27, 0x17, 0x3C, 0x00, 0x00, 0x00, 0x3C, 0x0F, 0x30, 0x16, 0x3C, 0x0F, 0x30, 0x21, 0x3C, 0x0F, 0x36, 0x27 });
            AddNewPalette("Giant", new byte[] { 0x3B, 0x0F, 0x30, 0x3C, 0x3B, 0x0F, 0x36, 0x27, 0x3B, 0x0F, 0x2A, 0x1A, 0x3B, 0x0F, 0x31, 0x21, 0x3B, 0x00, 0x00, 0x00, 0x3B, 0x0F, 0x30, 0x16, 0x3B, 0x0F, 0x30, 0x2A, 0x3B, 0x0F, 0x36, 0x27 });
            AddNewPalette("Ice", new byte[] { 0x31, 0x0F, 0x30, 0x3C, 0x31, 0x0F, 0x30, 0x27, 0x31, 0x0F, 0x30, 0x2A, 0x31, 0x0F, 0x30, 0x12, 0x31, 0x00, 0x00, 0x00, 0x31, 0x0F, 0x30, 0x16, 0x31, 0x0F, 0x30, 0x2A, 0x31, 0x0F, 0x36, 0x27 });
            AddNewPalette("Cloudy", new byte[] { 0x30, 0x0F, 0x30, 0x3C, 0x30, 0x0F, 0x36, 0x27, 0x30, 0x0F, 0x2A, 0x1A, 0x30, 0x0F, 0x12, 0x21, 0x30, 0x00, 0x00, 0x00, 0x30, 0x0F, 0x30, 0x16, 0x30, 0x0F, 0x30, 0x2A, 0x30, 0x0F, 0x36, 0x27 });
            AddNewPalette("Underground", new byte[] { 0x0F, 0x0F, 0x30, 0x3C, 0x0F, 0x06, 0x36, 0x27, 0x0F, 0x1C, 0x2C, 0x2A, 0x0F, 0x1C, 0x31, 0x21, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x1C, 0x30, 0x16, 0x0F, 0x1C, 0x30, 0x2A, 0x0F, 0x1C, 0x36, 0x27 });
        }

        public void AddNewPalette(string name)
        {
            PaletteInfo pi = new PaletteInfo();
            pi.Guid = Guid.NewGuid();
            pi.Name = name;
            Palettes.Add(pi);
            paletteLookup.Add(pi.Guid, pi);
            if (PaletteAdded != null) PaletteAdded(this, new TEventArgs<PaletteInfo>(pi));
        }

        public void AddNewPalette(string name, PaletteInfo basePalette)
        {
            PaletteInfo pi = new PaletteInfo();
            pi.Guid = Guid.NewGuid();
            pi.Name = name;
            Palettes.Add(pi);

            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    pi[i, j] = basePalette[i, j];
                }
            }

            paletteLookup.Add(pi.Guid, pi);
            if (PaletteAdded != null) PaletteAdded(this, new TEventArgs<PaletteInfo>(pi));
        }

        public void AddNewPalette(string name, byte[] paletteData)
        {
            PaletteInfo pi = new PaletteInfo();
            pi.Guid = Guid.NewGuid();
            pi.Name = name;
            Palettes.Add(pi);

            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    pi[i, j] = paletteData[ (i * 4) + j];
                }
            }

            paletteLookup.Add(pi.Guid, pi);
            if (PaletteAdded != null) PaletteAdded(this, new TEventArgs<PaletteInfo>(pi));
        }

        public void RemovePalette(PaletteInfo pi)
        {
            Palettes.Remove(pi);
            paletteLookup.Remove(pi.Guid);
            if (PaletteRemoved != null) PaletteRemoved(this, new TEventArgs<PaletteInfo>(pi));
        }

        #region IXmlIO Members

        public XElement CreateElement()
        {
            return CreateElement(true);
        }

        public XElement CreateElement(bool notify)
        {
            XElement palettes = new XElement("paletteinfo");
            foreach (var p in ProjectController.PaletteManager.Palettes)
            {
                palettes.Add(p.CreateElement());
            }

            if (notify)
            {
                if (PalettesSaved != null)
                {
                    PalettesSaved(this, null);
                }
            }

            return palettes;
        }

        public bool LoadFromElement(XElement e)
        {
            Palettes.Clear();
            paletteLookup.Clear();
            foreach (var p in e.Elements("palette"))
            {
                PaletteInfo pi = new PaletteInfo();
                pi.LoadFromElement(p);
                Palettes.Add(pi);
                paletteLookup.Add(pi.Guid, pi);
            }
            return true;
        }

        #endregion
    }
}
